/**
 * @file    drv_flash.c
 * @brief   flash驱动
 * @author  name
 * @version 1.0.1
 * @date    2023-04-14
 * 
 * @copyright Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version   <th>Author   <th>Description
 * <tr><td>2023-04-14 <td>1.0.1     <td>Liuwei   <td>首次创建
 * </table>
 */

/* includes ------------------------------------------------------------------*/
#include "drv_flash.h"
#include "drv_wdg.h"
/* macro/define --------------------------------------------------------------*/
#define FALSH_TRY_TIME        (3)
/* typedef -------------------------------------------------------------------*/

/* local functions -----------------------------------------------------------*/

/* static variables ----------------------------------------------------------*/

/* global variables ----------------------------------------------------------*/

/** ------------------------------------------------------------------------- *
  *                             Global function
 ** ------------------------------------------------------------------------- */

/**
 * @brief flash驱动初始化
 */
void drv_flash_init(void)
{
	SYS_UnlockReg();
	FMC_Open(); 
	FMC_ENABLE_AP_UPDATE(); 
	SYS_LockReg();
}

/**
 * @brief  擦除flash区域块
 * @param  start_addr : 起始地址
 * @param  end_addr : 结束地址
 */	
uint8_t drv_flash_erase_area(uint32_t start_addr , uint32_t end_addr)
{
	uint32_t addr_idx = 0;
	uint8_t try_times = 0;
	uint8_t ret = 0;
	uint8_t flag = 0;
	
	SYS_UnlockReg();
	for (addr_idx = start_addr; (addr_idx < end_addr) && (addr_idx < FMC_APROM_END); addr_idx += FMC_FLASH_PAGE_SIZE)
	{
		try_times = 0;
		do
		{
			ret = FMC_Erase(addr_idx);
			++ try_times ;
			drv_wdg_feed();
		}while((try_times < FALSH_TRY_TIME) && (ret != 0));
		
		if((try_times >= FALSH_TRY_TIME) || (ret != 0))
		{
			flag = 1;
			break;
		}
	}
	
	SYS_LockReg();
	
	return flag;
}

/**
 * @brief  读取flash区域块
 * @param  buf:存储缓冲区
 * @param  read_size:读取大小
 */
void drv_flash_read_data(uint32_t addr , uint8_t *buf , uint32_t size)
{
	uint32_t read_data = {0};
	uint32_t i = 0;
	
	SYS_UnlockReg();
	
	for( i = 0;i < size; i += 4)
	{
		read_data = FMC_Read(i + addr); 
		buf[i] = read_data ;
		buf[i + 1] = read_data >> 8;
		buf[i + 2] = read_data >> 16;
		buf[i + 3] = read_data>> 24;
	}
	SYS_LockReg();
}

/**
 * @brief  写flash区域块
 * @param  buf:存储缓冲区
 * @param  size:写入大小
 */	
uint8_t drv_flash_write_data(uint32_t addr , uint8_t *buf , uint32_t size)
{
	uint8_t try_times = 0;
	uint8_t ret = 0;
	uint32_t buf_addr = 0;
	uint32_t idx = 0;
	uint32_t wr_fls_data = 0;
	
	SYS_UnlockReg();
	for (idx = addr; idx < size + addr ; idx += 4)
    {
		try_times = 0;
		do
		{
			wr_fls_data = *(uint32_t *)&buf[buf_addr];
			ret = FMC_Write(idx , wr_fls_data);
			++ try_times ;
		}while((try_times < FALSH_TRY_TIME) && (ret != 0));
		
		if((try_times >= FALSH_TRY_TIME) && ( ret != 0))
		{
			SYS_LockReg();
			return 1;
		}
		
		buf_addr += 4;
    }
	
	SYS_LockReg();
	
	return 0;
}

/**
 * @brief  校验flash区域块
 * @param  start_addr : 起始地址
 * @param  end_addr ：结束地址
 * @param  buf : 校验数据缓冲区
 */	
uint8_t drv_flash_verify_data(uint32_t start_addr, uint32_t end_addr , uint8_t *buf)
{
	uint32_t u32Addr = 0;               /* flash address */
	uint8_t try_times = 0;
	uint32_t buf_addr = 0;
	uint32_t wr_data = 0;
	uint32_t rd_data = 0;
	
	SYS_UnlockReg(); 
    for (u32Addr = start_addr; u32Addr < end_addr; u32Addr += 4)
    {
		try_times = 0;
		do
		{
			rd_data = FMC_Read(u32Addr);
		}while((g_FMC_i32ErrCode != 0) && ( ++ try_times <= FALSH_TRY_TIME));
		
		if((g_FMC_i32ErrCode != 0) || ( ++ try_times > FALSH_TRY_TIME))
		{
			break;
		}
		
		wr_data = *(uint32_t *)&buf[buf_addr];
        if (rd_data != wr_data)     /* Verify if data matched. */
        {
			SYS_LockReg(); 
			return 1;
        }
		
		buf_addr += 4;
    }
	
	SYS_LockReg(); 
    return 0;                          /* data verify OK */
}

/**
 * @brief  关闭FLASH模块
 * @param  buf:存储缓冲区
 * @param  size:写入大小
 */	
void drv_flash_close(void)
{
	SYS_UnlockReg(); 
	
	FMC_DISABLE_AP_UPDATE();
	
	FMC_Close();
	
	SYS_LockReg(); 
}

/**
 * @brief 测试FALSH读写
 */
void drv_flash_wr_test(void)
{
	#define FLASH_TEST_SIZE      512
	#define FLASH_TEST_START     0x4000
	
	static uint32_t idx = 0;
	static uint32_t i = 0;
	uint8_t wr_buf[FLASH_TEST_SIZE];
	static uint16_t true_times = 0;

	if(FLASH_TEST_START + idx >= 0x40000)
		idx = 0;
	
	drv_flash_erase_area(FLASH_TEST_START + idx , FLASH_TEST_START + idx + 1);
	
	for( i = 0;i < FLASH_TEST_SIZE; ++ i)
	{
		wr_buf[i] = true_times + i;
	}
		
	drv_flash_write_data(idx + FLASH_TEST_START , wr_buf , FLASH_TEST_SIZE);
	
	if(0 == drv_flash_verify_data(idx + FLASH_TEST_START , idx + FLASH_TEST_START + FLASH_TEST_SIZE , wr_buf))
		true_times ++ ;
	else
	{
		printf("flash test error addr :0x%x\n" , idx + FLASH_TEST_START);
		while(1);
	}
		
	printf("success: %d ,test_addr :0x%x\n" ,true_times , idx + FLASH_TEST_START);
		
	idx += FLASH_TEST_SIZE;
}
/** ------------------------------------------------------------------------- *
  *                              Local function
 ** ------------------------------------------------------------------------- */	
 
/********** Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD *********/
